﻿using Engine;
using Game;

namespace NekoMeko.Common
{
	public class ShoulderSurfingCamera(GameWidget gameWidget) : BasePerspectiveCamera(gameWidget)
	{
		public override bool UsesMovementControls => false;
		public override bool IsEntityControlEnabled => true;

		Vector3 m_position;

		public override void Activate(Camera previousCamera)
		{
			m_position = previousCamera.ViewPosition;
			SetupPerspectiveCamera(m_position, previousCamera.ViewDirection, previousCamera.ViewUp);
		}

		public override void Update(float dt)
		{
			if (GameWidget.Target == null)
			{
				return;
			}
			var matrix = Matrix.CreateFromQuaternion(GameWidget.Target.ComponentCreatureModel.EyeRotation);
			matrix.Translation = GameWidget.Target.ComponentCreatureModel.EyePosition;// GameWidget.Target.ComponentBody.Position + 0.9f * GameWidget.Target.ComponentBody.BoxSize.Y * Vector3.UnitY;
			float afterNum = 2f, frontNum = 4f;
			Vector3 v = -afterNum * matrix.Forward + 0.0f * matrix.Up + 1f * matrix.Right;//相机位置偏移
			Vector3 cameraPosition = matrix.Translation + v;//相机位置
			if (Vector3.Distance(cameraPosition, m_position) < 10f)
			{
				Vector3 v2 = cameraPosition - m_position;
				float s = 3f * dt;
				m_position += s * v2;
			}
			else
			{
				m_position = cameraPosition;
			}
			Vector3 lookAt = matrix.Translation + matrix.Forward * frontNum;//相机看向位置
			Vector3 forward = Vector3.Normalize(m_position - lookAt);//相机正前方
			Vector3 right = Vector3.Normalize(Vector3.Cross(forward, Vector3.UnitY));//相机右方
			Vector3 up = Vector3.Normalize(Vector3.Cross(forward, right));//相机上方
			//射线检测地形防止摄像机穿模
			float? terrainDistance = null;
			SubsystemTerrain subsystemTerrain = GameWidget.SubsystemGameWidgets.SubsystemTerrain;
			//float d_l2c = Vector3.Distance(lookAt, cameraPosition);
			//float d_c2s = d_l2c * afterNum / (frontNum + afterNum);
			Vector3 start = matrix.Translation;// cameraPosition + forward * d_c2s;
			Vector3 end = cameraPosition;// start + forward + Vector3.Normalize(forward) * 0.5f;
			TerrainRaycastResult? terrainRaycastResult = subsystemTerrain.Raycast(start, end, useInteractionBoxes: false, skipAirBlocks: true, delegate (int value, float distance)
			{
				Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
				for (int k = 0; k < 6; k++)
				{
					if (!block.IsFaceTransparent(subsystemTerrain, k, value))
					{
						return true;
					}
				}
				return false;
			});
			if (terrainRaycastResult.HasValue)
			{
				terrainDistance = terrainDistance.HasValue ? MathUtils.Min(terrainDistance.Value, terrainRaycastResult.Value.Distance) : terrainRaycastResult.Value.Distance;
			}
			Vector3 vector5 = !terrainDistance.HasValue
				? cameraPosition
				: matrix.Translation + Vector3.Normalize(forward) * MathUtils.Max(terrainDistance.Value - 1.5f, 0.2f);
			SetupPerspectiveCamera(vector5, lookAt - vector5, Vector3.UnitY);
		}
	}
}

